#!usr/bin/env python
# -*- coding:utf-8 _*-
"""
@author:zhengxin
@file: 06_Pandas_JSON.py
@time: 2025/1/13  15:53
# @describe: Pandas JSON
"""

"""
        操作	                    方法	                    说明
从 JSON 文件/字符串读取数据	pd.read_json()          从 JSON 数据中读取并加载为 DataFrame
将 DataFrame 转换为 JSON	    DataFrame.to_json() 	将 DataFrame 转换为 JSON 格式的数据，可以指定结构化方式
支持 JSON 结构化方式	        orient 参数	            支持多种结构化方式，如 split、records、columns

"""

"""
从 JSON 文件/字符串加载数据
    pd.read_json() - 读取 JSON 数据
    read_json() 用于从 JSON 格式的数据中读取并加载为一个 DataFrame。
        它支持从 JSON 文件、JSON 字符串或 JSON 网址中加载数据。
    
    语法格式：
    
import pandas as pd

df = pd.read_json(
    path_or_buffer,      # JSON 文件路径、JSON 字符串或 URL
    orient=None,         # JSON 数据的结构方式，默认是 'columns'
    dtype=None,          # 强制指定列的数据类型
    convert_axes=True,   # 是否转换行列索引
    convert_dates=True,  # 是否将日期解析为日期类型
    keep_default_na=True # 是否保留默认的缺失值标记
)

参数说明：
        参数	                                说明	                                                默认值
    path_or_buffer	    JSON 文件的路径、JSON 字符串或 URL	                                            必需参数
    orient	            定义 JSON 数据的格式方式。常见值有 split、records、index、columns、values。	    None（根据文件自动推断）
    dtype	            强制指定列的数据类型	                                                        None
    convert_axes	    是否将轴转换为合适的数据类型	                                                    True
    convert_dates	    是否将日期解析为日期类型	                                                    True
    keep_default_na	    是否保留默认的缺失值标记（如 NaN）	                                            True
    

常见的 orient 参数选项:
    
    orient 值	                JSON 格式示例	                                    描述
    split	    {"index":["a","b"],"columns":["A","B"],"data":[[1,2],[3,4]]}	        使用键 index、columns 和 data 结构
    records	    [{"A":1,"B":2},{"A":3,"B":4}]	                                        每个记录是一个字典，表示一行数据
    index	    {"a":{"A":1,"B":2},"b":{"A":3,"B":4}}	                                使用索引为键，值为字典的方式
    columns	    {"A":{"a":1,"b":3},"B":{"a":2,"b":4}}	                                使用列名为键，值为字典的方式
    values	    [[1,2],[3,4]]	                                                        只返回数据，不包括索引和列名
"""
# 从JSON 文件加载数据
import pandas as pd

df = pd.read_json("data/ sites.json")
# 返回 DataFrame 类型的数据
print(df.to_string())


""" 将 Python 字典转化为 DataFrame 数据： """
dict_s = {
    "col1": {"row1": 1, "row2": 2, "row3": 3},
    "col2": {"row1": "x", "row2": "y", "row3": "z"}
}
# 读取 Json 转为 DataFrame
df = pd.DataFrame(dict_s)
print(df)


""" 从 URL 中读取 JSON 数据： """
import pandas as pd

URL = "https://static.jyshare.com/download/sites.json"
df = pd.read_json(URL)
print(df)



""" 从 JSON 字符串加载数据： """
import pandas as pd
from io import StringIO


json_data = '''
[
  {"Name": "Alice", "Age": 25, "City": "New York"},
  {"Name": "Bob", "Age": 30, "City": "Los Angeles"},
  {"Name": "Charlie", "Age": 35, "City": "Chicago"}
]
'''
# 使用StringIO将字符串转换为类文件对象
json_string_io = StringIO(json_data)
df = pd.read_json(json_string_io)
print(df)



""" 从 JSON 数据读取（指定 orient 为 records）： """
import pandas as pd

# JSON 数据
json_data = '''
[
  {"Name": "Alice", "Age": 27, "City": "New York"},
  {"Name": "Bob", "Age": 31, "City": "Los Angeles"},
  {"Name": "Charlie", "Age": 38, "City": "Chicago"}
]
'''
json_string_io = StringIO(json_data)
df = pd.read_json(json_string_io, orient="records")
print(df)




""" 内嵌的 JSON 数据  """
import json
df = pd.read_json("data/nested_list.json")
print(df)

with open("data/nested_list.json", "r") as f:
    data = json.loads(f.read())

# json_normalize() 方法将内嵌的数据完整的解析出来：
# json_normalize() 使用了参数 record_path 并设置为 ['students'] 用于展开内嵌的 JSON 数据 students。
df_nested_list = pd.json_normalize(data, record_path=['students'])
print(df_nested_list)

# 展示 school_name 和 class 数据
df_nested_list_1 = pd.json_normalize(
    data,
    record_path =['students'],
    meta=['school_name', 'class']
)
print(df_nested_list_1)
print("---"*40)






""" 嵌套了列表和字典的Json数据 """
# nested_mix.json 文件转换为 DataFrame：
with open("data/nested_mix.json", "r") as f:
    data = json.loads(f.read())

df = pd.json_normalize(
    data,
    record_path=["students"],
    meta=[
        'class',
        ['info', 'president'],
        ['info', 'contacts', 'tel']
    ]
)
print(df)






""" 读取内嵌中的 math 字段： """
# glom 模块允许我们使用 . 来访问内嵌对象的属性
import pandas as pd
from glom import glom

df = pd.read_json("data/nested_deep.json")
data = df["students"].apply(lambda row: glom(row, "grade.math"))
print(data)




""" 
将 DataFrame 转换为 JSON
    DataFrame.to_json() - 将 DataFrame 转换为 JSON 数据
to_json() 方法用于将 DataFrame 转换为 JSON 格式的数据，可以指定 JSON 的结构化方式。

语法格式：

df.to_json(
    path_or_buffer=None,    # 输出的文件路径或文件对象，如果是 None 则返回 JSON 字符串
    orient=None,            # JSON 格式方式，支持 'split', 'records', 'index', 'columns', 'values'
    date_format=None,       # 日期格式，支持 'epoch', 'iso'
    default_handler=None,   # 自定义非标准类型的处理函数
    lines=False,            # 是否将每行数据作为一行（适用于 'records' 或 'split'）
    encoding='utf-8'        # 编码格式
)
 """
import pandas as pd

df = pd.DataFrame({
    'Name': ['Alice', 'Bob', 'Charlie'],
    'Age': [25, 30, 35],
    'City': ['New York', 'Los Angeles', 'Chicago']
})

# 将 DataFrame 转换为 JSON 字符串
json_str = df.to_json()
print(json_str)





""" 将 DataFrame 转换为 JSON 文件（指定 orient='records'）： """
import pandas as pd

# 创建 DataFrame
df = pd.DataFrame({
    'Name': ['Alice', 'Bob', 'Charlie'],
    'Age': [25, 30, 35],
    'City': ['New York', 'Los Angeles', 'Chicago']
})

# 将 DataFrame 转换为 JSON 文件，指定 orient='records'
df.to_json('data/data.json', orient='records', lines=False)




""" 将 DataFrame 转换为 JSON 并指定日期格式： """
import pandas as pd

df = pd.DataFrame({
    'Name': ['Alice', 'Bob', 'Charlie'],
    'Date': pd.to_datetime(['2021-01-01', '2022-02-01', '2023-03-01']),
    'Age': [25, 30, 35]
})

# 将 DataFrame 转换为 Json，并指定日期格式为"iso"
json_str = df.to_json(date_format="iso")
print(json_str)